#include "sr501.h"

static int sr501_release(struct inode *inode, struct file *file);
static int sr501_fasync(int fd, struct file *file, int on);
static ssize_t sr501_read(struct file *file, char __user *buf, size_t len, loff_t *pos);

static void sr501_work(struct work_struct *w);

static int sr501_probe(struct platform_device *pdev);
static int sr501_remove(struct platform_device *pdev);

//设备号
static dev_t sr501_num;
//cdev对象
static struct cdev sr501_cdev;
//class对象
static struct class *sr501_class;
//操作函数
static struct file_operations sr501_ops = {
	.owner = THIS_MODULE,
	.release = sr501_release,
	.fasync = sr501_fasync,
	.read = sr501_read,
};
//SR501资源
struct sr501_handle sr501_handle[SR501_NUMBER];

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id sr501_of_match[] = {
	{.compatible = "atk,sr501"},
	{ /* Sentinel */ }
};
//平台驱动
struct platform_driver sr501_drv = {
	.driver = {
		.name = "sr501",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = sr501_of_match,
	},
	.probe = sr501_probe,
	.remove = sr501_remove,
};

static int sr501_release(struct inode *inode, struct file *file)
{
	sr501_fasync(-1, file, 0);
	return 0;
}

static int sr501_fasync(int fd, struct file *file, int on)
{
	uint32_t id;
	
	id = MINOR(file->f_inode->i_rdev);
	if(id > SR501_NUMBER)
		return -EINVAL;

	return fasync_helper(fd, file, on, &sr501_handle[id].fasync);
}

static ssize_t sr501_read(struct file *file, char __user *buf, size_t len, loff_t *pos)
{
	uint32_t id;

	id = MINOR(file->f_inode->i_rdev);
	if((id > SR501_NUMBER) || (len < sizeof(int))
		return -EINVAL;

	//以阻塞式打开，则加入等待队列并休眠
	if(!(file->f_flags & O_NONBLOCK))
	{
		sr501_handle[id].update = 0;
		if(wait_event_interruptible(sr501_handle[id].wait_queue, sr501_handle[id].update))
			return -ERESTARTSYS;
	}

	if(copy_to_user(buf, &sr501_handle[id].state, sizeof(int)))
		return -EFAULT;

	return sizeof(int);
}

static void sr501_work(struct work_struct *w)
{
	struct sr501_handle *sr501 = container_of(w, struct sr501_handle, work);

	//读取输入状态
	if(gpio_get_value(sr501->gpio) == sr501->gpio_active)
		sr501->state = 1;
	else
		sr501->state = 0;
	//发送信号通知相应进程
	kill_fasync(&sr501->fasync, SIGIO, POLL_IN);
	//等待事件的进程
	sr501->update = 1;
	wake_up_interruptible(&sr501->wait_queue);
}

static irqreturn_t sr501_handler(int irq, void *dev)
{
	uint32_t id;

	id = (uint32_t)dev;

	//调度工作队列
	schedule_work(&sr501_handle[id].work);

	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

static int sr501_thread(void *arg)
{
	int last_state;
	uint32_t id;

	id = (uint32_t)arg;
	last_state = 0;
	while(!kthread_should_stop())
	{
		//读取输入状态
		if(gpio_get_value(sr501_handle[id].gpio) == sr501_handle[id].gpio_active)
			sr501_handle[id].state = 1;
		else
			sr501_handle[id].state = 0;

		//检查输入是否改变
		if(last_state != sr501_handle[id].state)
		{
			//发送信号通知相应进程
			kill_fasync(&sr501_handle[id].fasync, SIGIO, POLL_IN);
			//等待事件的进程
			sr501_handle[id].update = 1;
			wake_up_interruptible(&sr501_handle[id].wait_queue);
		}

		//记录此次状态，方便下次对比
		last_state = sr501_handle[id].state;

		//休眠
		msleep_interruptible(10);
	}

	return 0;
}

//设备和驱动匹配成功执行
static int sr501_probe(struct platform_device *pdev)
{
	int result;
	uint32_t id;
	uint32_t irq_flags;
	enum of_gpio_flags gpio_flags;
	struct device *device;

	printk("%s\r\n", __FUNCTION__);

	//获取设备ID号
	result = of_property_read_u32(pdev->dev.of_node, "id", &id);
	if(result != 0)
	{
		printk("get dev id failed\r\n");
		return result;
	}
	if(id > SR501_NUMBER)
	{
		printk("dev id invalid\r\n");
		return -EINVAL;
	}
	if(sr501_handle[id].use_flag) 
	{
		printk("dev id repetition\r\n");
		return -EINVAL;
	}
	pdev->id = id;

	//标记为已占用
	sr501_handle[id].use_flag = 1;

	//初始化等待队列
	init_waitqueue_head(&sr501_handle[id].wait_queue);

	//获取GPIO号
	sr501_handle[id].gpio = of_get_named_gpio_flags(pdev->dev.of_node, "gpios", 0, &gpio_flags);
	if(sr501_handle[id].gpio < 0)
	{
		sr501_handle[id].use_flag = 0;
		printk("get gpio failed\r\n");
		return sr501_handle[id].gpio;
	}
	//提取GPIO活跃电平
	sr501_handle[id].gpio_active = (gpio_flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1;
	//申请GPIO
	result = gpio_request(sr501_handle[id].gpio, "sr501");
	if(result != 0)
	{
		sr501_handle[id].use_flag = 0;
		printk("request gpio failed\r\n");
		return result;
	}
	//设置GPIO为输入
	gpio_direction_input(sr501_handle[id].gpio);

	sr501_handle[id].irq = of_irq_get(pdev->dev.of_node, 0);
	if (sr501_handle[id].irq > 0)
	{
		printk("id: %d,use interrupt.\r\n", id);
		//使用中断
		//初始化工作队列
		INIT_WORK(&sr501_handle[id].work, sr501_work);
		//获取中断触发方式
		irq_flags = irq_get_trigger_type(sr501_handle[id].irq);
		if(irq_flags == IRQF_TRIGGER_NONE)
			irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
		//注册中断
		result = request_irq(sr501_handle[id].irq, sr501_handler, irq_flags, "sr501_intr", (void*)id);
		if(result != 0)
		{
			gpio_free(sr501_handle[id].gpio);
			sr501_handle[id].use_flag = 0;
			printk("request irq failed\r\n");
			return result;
		}
	}
	else
	{
		printk("id: %d,use kthread.\r\n", id);
		//使用内核线程
		//创建内核线程
		sr501_handle[id].kthread = kthread_create(sr501_thread, (void*)id, "thread_test%d", id);
		if(IS_ERR(sr501_handle[id].kthread))
		{
			gpio_free(sr501_handle[id].gpio);
			sr501_handle[id].use_flag = 0;
			printk("create sr501_thread failed\r\n");
			return PTR_ERR(sr501_handle[id].kthread);
		}
		//启动内核线程
		wake_up_process(sr501_handle[id].kthread);
	}

	//创建设备文件，将ID作为此设备的次设备号
	device = device_create(sr501_class, NULL, sr501_num+id, NULL, "sr501-%d", id);
	if(IS_ERR(device))
	{
		if (sr501_handle[id].irq > 0)
			free_irq(sr501_handle[id].irq, (void*)id);
		else
			kthread_stop(sr501_handle[id].kthread);
		gpio_free(sr501_handle[id].gpio);
		sr501_handle[id].use_flag = 0;
		printk("device create failed");
		return PTR_ERR(device);
	}

	sr501_handle[id].state = 0;

	return 0;
}

//设备或驱动卸载时执行
static int sr501_remove(struct platform_device *pdev)
{
	uint32_t id;

	printk("%s\r\n", __FUNCTION__);

	id = pdev->id;
	if(!sr501_handle[id].use_flag)
	{
		printk("verification failed\r\n");
		return -EINVAL;
	}

	device_destroy(sr501_class, sr501_num+id);
	if (sr501_handle[id].irq > 0)
		free_irq(sr501_handle[id].irq, (void*)id);
	else
		kthread_stop(sr501_handle[id].kthread);
	gpio_free(sr501_handle[id].gpio);

	sr501_handle[id].use_flag = 0;

	return 0;
}

static int __init sr501_drv_init(void)
{
	int i;
	int err = 0;

	printk("%s\r\n", __FUNCTION__);

	for(i=0; i<SR501_NUMBER; i++)
	{
		sr501_handle[i].use_flag = 0;
		sr501_handle[i].state = 0;
	}

	//根据次设备号起始值动态注册字符设备号
	err = alloc_chrdev_region(&sr501_num, 0, SR501_NUMBER, "atk,sr501");
	if(err != 0)
	{
		printk("alloc chrdev failed\r\n");
		return err;
	}
	printk("first device major %d, minor %d\r\n", MAJOR(sr501_num), MINOR(sr501_num));

	//初始化CDEV对象
	cdev_init(&sr501_cdev, &sr501_ops);
	//向系统添加CDEV对象
	err = cdev_add(&sr501_cdev, sr501_num, SR501_NUMBER);
	if(err != 0)
	{
		unregister_chrdev_region(sr501_num, SR501_NUMBER);
		printk("add cdev failed\r\n");
		return err;
	}

	//创建class对象
	sr501_class = class_create(THIS_MODULE, "sr501,class");
	if(IS_ERR(sr501_class))
	{
		cdev_del(&sr501_cdev);
		unregister_chrdev_region(sr501_num, SR501_NUMBER);
		printk("class create failed");
		return PTR_ERR(sr501_class);
	}

	//注册平台驱动
	err = platform_driver_register(&sr501_drv);
	if(err != 0)
	{
		class_destroy(sr501_class);
		cdev_del(&sr501_cdev);
		unregister_chrdev_region(sr501_num, SR501_NUMBER);
		printk("add cdev failed\r\n");
		return err;
	}
	return err;
}

static void __exit sr501_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&sr501_drv);
	//销毁class对象
	class_destroy(sr501_class);
	//从系统删除CDEV对象
	cdev_del(&sr501_cdev);
	//注销字符设备号
	unregister_chrdev_region(sr501_num, SR501_NUMBER);
}

module_init(sr501_drv_init);
module_exit(sr501_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("sr501_dev");
